from Searcher import Searcher
from pygene.gene import FloatGene, FloatGeneMax, rndPair
from pygene.gamete import Gamete
from pygene.organism import Organism, MendelOrganism
from pygene.population import Population
from subprocess import *


class GASearcher(Searcher):
    """ search best parameters using genetic algorithm"""
    def __init__(self,dataDisplayer, cmdline, options, *ranges):
        super(GASearcher, self).__init__()
        self.dataDisplayer = dataDisplayer
        self.cmdline = cmdline
        self.ranges = ranges
        self.options = options


        class LogGeneX(FloatGene):
            mutProb = 0.1
            randMin = ranges[0][0]
            randMax = ranges[0][1]
            mutAmt = ranges[0][2]

        class LogGeneY(FloatGene):
            mutProb = 0.1
            randMin = ranges[1][0]
            randMax = ranges[1][1]
            mutAmt = ranges[1][2]

        class LogGASearcher(Organism):
            """docstring for LogGASearcher"""
            #genome = {'x':LogGene(mutProb = 0.1, randMin = self.ranges[0][0], \
                    #randMax = self.ranges[0][1], mutAmt = self.ranges[0][2]), \
                    #'y':LogGene(mutProb = 0.1, randMin = self.ranges[1][0], \
                    #randMax = self.ranges[1][1], mutAmt = self.ranges[1][2])}
            genome = {'x':LogGeneX, 'y':LogGeneY}

            def fitness(self):
                """
                Return the fitness level of this organism, as a float
                Should return a number from 0.0 to infinity, where
                0.0 means 'perfect'
                Organisms should evolve such that 'fitness' converges
                to zero.
                """
                #cmd = self.owner.__class__.cmdline
                cmd = cmdline
                cmd = cmd.replace('cost', str(2.0**self['x']))
                cmd = cmd.replace('gamma', str(2.0**self['y']))
                result = Popen(cmd,shell=True,stdout=PIPE).stdout
                for line in result.readlines():
                    if str(line).find("Cross") != -1:
                        return 1.0 - float(line.split()[-1][0:-1])/100


        class logGASearcherPopulation(Population):
            """docstring for logGASearcherPopulation"""
            species = LogGASearcher
            initPopulation = int(self.options['initPopulation'])
            numNewOrganisms = int(self.options['numNewOrganisms'])
            childCount = int(self.options['childCount'])
            childCull = int(self.options['childCull'])
            mutants = float(self.options['mutants'])
            mutateAfterMating = self.options['mutateAfterMating']
            incest = int(self.options['incest'])

        self.pop = logGASearcherPopulation()


    def search(self):
        """docstring for search"""
        desiredFitness = 1.0 - float(self.options['desiredRate'])/100
        i = 0
        b = None
        while True:
            b = self.pop.best()
            #print "generation %s: %s best=%s average=%s)" % ( i, repr(b), b.fitness(), self.pop.fitness())
            print "generation %s: %s best rate=%s average=%s" % ( i, repr(b), 1.0-b.fitness(), 1.0 - self.pop.fitness())
            print "best cost, gamma = (%s, %s)" % (2.0**b['x'], 2.0**b['y'])
            #self.dataDisplayer.writeConsole("generation %s: %s best rate=%s average=%s" % ( i, repr(b), 1.0-b.fitness(), 1.0 - self.pop.fitness()))
            self.dataDisplayer.writeConsole("generation %s: best rate=%s   average rate=%s" % ( i, 1.0-b.fitness(), 1.0 - self.pop.fitness()))
            self.dataDisplayer.writeConsole("best cost, gamma = (%s, %s)" % (2.0**b['x'], 2.0**b['y']))
            self.dataDisplayer.drawGACurve(i, 1.0-b.fitness())
            #self.dataDisplayer.drawGACurve(0,0)
            if b.fitness() <= desiredFitness: # rate > 60%
                print "cracked!"
                break
            i += 1
            self.pop.gen()

        return 2.0**b['x'], 2.0**b['y']
    #def search(self):
        #"""docstring for search"""
        #for i in range(12):
            #for i in range(5000000):
                    #cmd = 'dir'
                    #2*10/2.3
            #self.dataDisplayer.drawGACurve(0,0)

        return 0,0

#class LogGene(FloatGene):
    #"""docstring for Gene"""
    #def __init__(self, **kw):
        #super(LogGene, self).__init__()
        #if kw.has_key('mutProb'):
            #mutProb = kw['mutProb']
        #else:
            #mutProb = 0.1

        #if kw.has_key('randMin'):
            #randMin = kw['randMin']
        #else:
            #randMin = -5

        #if kw.has_key('randMax'):
            #randMax = kw['randMax']
        #else:
            #randMax = 15

        #if kw.has_key('mutAmt'):
            #mutAmt = kw['mutAmt']
        #else:
            #mutAmt = 1

class LogGeneZ(FloatGene):
    mutProb = 0.1
    randMin = 0
    randMax = 5
    mutAmt = 0.1
